<?php
namespace DRY\NoSQL;

if(!class_exists("\\Memcache"))
	throw new \Exception("Memcache extension not available !");

/**
 * Data storage system for Cache module which uses Memcache PECL extension and Memcached server to store data
 *
 * @author Wavetrex <wavetrex@gmail.com>
 * @link http://www.donrey.net/Documentation/Structure/Modules/authentication.html#files
 * @license [GPL v3] http://www.gnu.org/licenses/gpl-3.0.html
 * @version 1.0.dev
 * @package DonReY
 * @subpackage Module.NoSQL
 */
class Storage_Memcached extends \Memcache implements Storage
{
	const
		// Flags
		FLAG_PERSISTENT = false,
		FLAG_LIMITEDSTORAGE = true,
		FLAG_FAST = true
		;

	private $_cache_active = false;

	private $_serializer = null;

	public function __construct(\SimpleXMLElement $CFG)
	{
		// makes the connection to the Memcached server
		$port = isset($CFG-> server['port'])?(int)$CFG-> server['port']:11211;
		$timeout =isset($CFG-> server['timeout'])?(int)$CFG-> server['timeout']:1;

		if($CFG-> server['persistent'])
			$r = @$this-> pconnect((string)$CFG-> server, $port, $timeout);
		else
			$r = @$this-> connect((string)$CFG-> server, $port, $timeout);

		if($r == false) {
			\DRY\Water::dump("Server {$CFG-> server}:{$port} unavailable", 'Cache::Memcache', null, 'warning');
		} else {
			$this->_cache_active = true;
			\DRY\Water::dump("Connection estabilished to {$CFG-> server}", 'Cache::Memcache', null, 'notice');
		}

		// check if alternative serializer is used for non-strings, non-int
		if(isset($CFG-> serializer))
			$this->_serializer = (string)$CFG-> serializer;
	}

	private $_expire = 0; // default = 0 means no expire

	/**
	 * Sets the expiry time (in seconds) for all subsequent "set", "add", "replace" methods (if no other expire time has been specified)
	 * @param unknown_type $expire
	 */
	public function _Set_Expire($expire = 0)
	{
		$this->_expire = $expire;
	}

	public function set($key, $data, $expire = null)
	{
		if($this->_cache_active) {
			// custom serializer, before storing data
			if($this->_serializer) {
				if(!is_int($data) && !is_string($data)) {
					switch($this->_serializer) {
						case 'igbinary':
							$data = igbinary_serialize($data);
							break;
					}
					// also set a second key to indicate that this value is customly serialized
					parent::set('##serialized##'.$key, 1, null, is_null($expire)?$this->_expire:$expire);
				}
			}
			parent::set($key, $data, null, is_null($expire)?$this->_expire:$expire);
		}
	}

	public function get($key)
	{
		if(!$this->_cache_active)
			return null;

		$data = parent::get($key);
		if($this->_serializer) {
			$is_serialzied = parent::get('##serialized##'.$key);
			if($is_serialzied)
				switch($this->_serializer) {
					case 'igbinary':
						$data = igbinary_unserialize($data);
				}
		}
		return $data;
	}

	public function delete($key)
	{
		if($this->_cache_active)
			return parent::delete($key);
	}

	public function check($key)
	{
		if($this->_cache_active)
			return parent::get($key)!==false;
	}

	public function wait_For_Change($key, $timeout, $poll_interval = null)
	{
		if(!$this->_cache_active)
			return false;
	}
}
